#!/usr/bin/env python
# -*- coding: utf-8 -*-

import hashlib
import os

from datetime import datetime
from typing import Dict
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5
from Crypto.Hash import SHA
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
import base64
import json
from jsonpath import jsonpath
from random import choice

from commons.get_envinfo import env
from commons.logger import log
from config.path import CONF_DIR
from utils.requests_tools import HttpRequest
from config.path import DATA_DIR, PIC_DIR, VIDEO_DIR, EXCEL_DIR

appKey = env.get_value('SCRM', 'APP_KEY')
secret = env.get_value('SCRM', 'SECRET')
v = env.get_value('SCRM', 'VERSION')
dj_url = env.get_value("DJ+", "HOST")
a = HttpRequest()


def join_payload(
        params: Dict,
        source: str = 'scrm-home',
        client_type: str = None,
) -> Dict:
    """获取sign，添加到到请求body并返回

    :param params: 请求参数
    :param source: 请求来源
    :param client_type: 客户端类型
    :return: 返回更新后字典
    """
    # 公共参数
    fixed_params = {
        "v": v,
        "format": "json",
        "source": source,
        "appKey": appKey,
        'timestamp': get_now_time(),
    }

    # 小程序
    if client_type == 'wechat':
        fixed_params['locale'] = 'zh_CN'
        fixed_params['source'] = 'dj-wechat'
        fixed_params.pop('timestamp')  # 小程序不需要timestamp

    fixed_params.update(params)
    fixed_params.update({"sign": get_sign(fixed_params)})
    return fixed_params


def join_payload_didicb(payload: Dict) -> Dict:
    """获取sign，添加到到请求body并返回

    :param payload: 请求参数
    :type payload: Dict
    :return: 返回更新后字典
    :rtype: Dict
    """
    fixed_params = {
        "v": "1.0.0",
        "format": "json",
        "source": "glsx",
        "app_key": appKey,
        'timestamp': get_now_time(),
    }
    payload.update(fixed_params)
    payload.update({"sign": get_sign_md5(payload)})

    return payload


def wechat_join_payload(params: Dict,
                        source: str = "dj-wechat",
                        app_key: str = env.get_value('WechatZhc', 'APP_KEY'),
                        secret_str: str = secret) -> Dict:
    """
    智慧车生活
    获取sign，添加到到请求body并返回
    :param params: 请求参数
    :return: 返回更新后字典
    """
    # 公共参数
    fixed_params = {
        "v": v,
        "format": "json",
        "source": source,
        "locale": "zh_CN",
        "appKey": app_key,
    }

    fixed_params.update(params)
    fixed_params.update(
        {"sign": get_sign(payload=fixed_params, secret_str=secret_str)})
    return fixed_params


def wechat_equity_pay_join_payload(params: Dict) -> Dict:
    """
    智慧车生活权益支付回调接口
    获取sign，添加到到请求body并返回
    :param params: 请求参数
    :return: 返回更新后字典
    """
    sign = get_sign_rsa(params)
    params["sign"] = sign
    return params


def ent_join_payload(params: Dict) -> Dict:
    """
    嘀加企微端
    获取sign，添加到到请求body并返回
    :param params: 请求参数
    :return: 返回更新后字典
    """
    # 公共参数
    fixed_params = {
        "v": v,
        "format": "json",
        "source": "scrm-main",
        "locale": "zh_CN",
        "appKey": appKey,
        'timestamp': get_now_time(),
    }

    fixed_params.update(params)
    fixed_params.update({"sign": get_sign(fixed_params)})
    return fixed_params


def get_sign_md5(payload: Dict) -> str:
    """获取签名sign并返回

    :param payload: 请求参数，键值对字典
    :type payload: Dict
    """
    payload_str = sorted_payload_to_str(payload)
    sign = payload_str_md5(payload_str)
    return sign


def get_sign(payload: Dict, secret_str: str = secret) -> str:
    """获取签名sign并返回

    :param payload: 请求参数，键值对字典
    :type payload: Dict
    """
    payload_str = sorted_payload_to_str(payload)
    sign = payload_str_sha1(payload_str=payload_str, secret_str=secret_str)
    return sign


def sorted_payload_to_str(payload: Dict) -> str:
    """请求参数按照字母先后顺序排序，
    参数名和参数值连接后，得到拼装字符串

    :param payload: 请求参数，键值对字典
    :type payload: Dict
    :return: 返回拼接后的字符串
    :rtype: str
    """
    key_value_str = ''
    for key in sorted(payload):
        key_value_str += (key + str(payload[key]))

    return key_value_str


def payload_str_md5(payload_str: str) -> str:
    """将secret拼接到参数字符串头、尾进行md5加密后返回

    :param payload_str: 排序好的参数字符串
    :type payload_str: str
    :return: 加密后数据
    :rtype: str
    """
    # 待加密字符串
    unencrypted_str = secret + payload_str + secret

    # 使用md5 32位算法加密，转换为大写，返回最终的密钥
    md5_obj = hashlib.md5()
    md5_obj.update(unencrypted_str.encode('utf-8'))
    encrypted_str = md5_obj.hexdigest().upper()

    return encrypted_str


def payload_str_sha1(payload_str: str, secret_str: str = secret) -> str:
    """将secret拼接到参数字符串头、尾进行SHA1加密后返回

    :param payload_str: 排序好的参数字符串
    :type payload_str: str
    :return: 加密后数据
    :rtype: str
    """
    # 待加密字符串
    unencrypted_str = secret_str + payload_str + secret_str
    # 使用sha1算法加密，转换为大写，返回最终的密钥
    sha1_obj = hashlib.sha1()
    sha1_obj.update(unencrypted_str.encode('utf-8'))
    encrypted_str = sha1_obj.hexdigest().upper()

    return encrypted_str


def payload_str_rsa(payload: Dict):
    # 拼接公钥及排序请求参数
    public_key_str = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCHA6UKTThIhiysNTzWYKYs7kZ7jq2ExSqRSlH+x1jud71s6rWhgCQIZ+19MbtoMqaZ//pmlVBP6PBQ2OX3EwTNOFd+dkpfmg1FH1utNj6wQoGAk1sJCp7ayFmbf+1J0J6ZZLlfSu5tF5vpriF21ZsOgdWJM3Nv+qgdA9SgUAGHlQIDAQAB"
    sorted_key = sorted(payload.keys())
    payload_str = ''.join(map(lambda x: x + payload[x], sorted_key))
    payload_str = public_key_str + payload_str + public_key_str
    return payload_str


def get_sign_rsa(payload: Dict):
    payload_str = payload_str_rsa(payload)
    private_key = RSA.importKey(
        open(CONF_DIR + '/equity_public_key.pem').read())

    cipher = PKCS1_v1_5.new(private_key)  # 创建用于执行pkcs1_v1_5加密或解密的密码
    hash_data = SHA.new(payload_str.encode("utf8"))
    sign_str = cipher.sign(hash_data)
    sign = base64.b64encode(sign_str)
    return sign.decode('utf-8')


def get_now_time() -> int:
    """获取当前时间，并返回时间戳(13位毫秒级)

    :return: 当前时间戳
    :rtype: int
    """
    timestamp = int(datetime.now().timestamp() * 1000)
    return timestamp


def get_encrypt_password(raw_passwd: str) -> str:
    """原密码md5加密后返回

    :return: 返回加密密码
    :rtype: str
    """
    md5_obj = hashlib.md5()
    md5_obj.update(raw_passwd.encode(encoding='utf-8'))

    return md5_obj.hexdigest()


def encrypt_json_aes(encrypt_secret: str, json_data: dict):
    """
    AES加密请求参数
    ---------
    :param x:
    :param x:
    -------
    :return:

    """
    json_data = json.dumps(json_data)

    # 将密钥和数据转换为字节数组
    encrypt_secret = encrypt_secret.encode('utf-8')
    json_data = json_data.encode('utf-8')
    # 使用AES的CBC模式进行加密
    cipher = AES.new(encrypt_secret, AES.MODE_ECB)
    # 对数据进行填充
    padded_data = pad(json_data, AES.block_size, style="pkcs7")
    # 加密数据
    encrypted_data = cipher.encrypt(padded_data)
    # 将加密后的数据进行base64编码
    encrypted_data_base64 = base64.b64encode(encrypted_data)
    return encrypted_data_base64.decode('utf-8')
    # return encrypted_data_base64


def post_upload_dj(path, data=None, json=None, file=None, **kwargs):
    """
    PC端POST请求,上传文件(图片等)专用
    :param path:
    :param data:
    :param json:
    :param file:
    :param kwargs:
    :return:
    """
    url = dj_url + path
    data = {"method": "dj.api.common.uploadImg"}
    data = join_payload(data)
    data.update(file=get_pic_value())
    response = a.post_dj(url, data=data, json=json, **kwargs)
    return jsonpath(response.json(), "$..data")[0]


def video_upload_dj(path, data=None, json=None, file=None, **kwargs):
    """
    PC端POST请求,上传文件(图片等)专用
    :param path:
    :param data:
    :param json:
    :param file:
    :param kwargs:
    :return:
    """
    url = dj_url + path
    data = {"method": "dj.api.smartcarlife.common.uploadVideo"}
    data = join_payload(data)
    data.update(file=get_video_value())
    response = a.post_dj(url, data=data, json=json, **kwargs)
    return jsonpath(response.json(), "$..data")[0]


def get_excel_value(file: str):
    """
    解析编码Excel文件，生成file参数的值
    :param file:
    :return:
    """
    file_path = EXCEL_DIR / file
    with open(file_path, "rb") as f:
        content = f.read()

    content = base64.b64encode(content)
    # 获取文件后缀名称
    suffix_name = file.split(".")[-1]
    # file参数格式：文件名后缀 + @ + 文件内容进行base64编码后的字符串
    file_value = suffix_name + "@" + content.decode()
    return file_value


def get_pic_value():
    """
    解析编码图片文件，生成file参数的值
    :param file:
    :return:
    """
    files = os.listdir(PIC_DIR)
    file = choice(files)
    file_path = PIC_DIR / file
    with open(file_path, "rb") as f:
        content = f.read()

    content = base64.b64encode(content)
    # 获取文件后缀名称
    suffix_name = file.split(".")[-1]
    # file参数格式：文件名后缀 + @ + 文件内容进行base64编码后的字符串
    file_value = suffix_name + "@" + content.decode()
    return file_value


def get_video_value():
    """
            解析编码视频文件，生成file参数的值
            :param file:
            :return:
            """
    files = os.listdir(VIDEO_DIR)
    file = choice(files)
    file_path = VIDEO_DIR / file
    with open(file_path, "rb") as f:
        content = f.read()

    content = base64.b64encode(content)
    # 获取文件后缀名称
    suffix_name = file.split(".")[-1]
    # file参数格式：文件名后缀 + @ + 文件内容进行base64编码后的字符串
    file_value = suffix_name + "@" + content.decode()
    return file_value


if __name__ == '__main__':
    a = get_encrypt_password('123')
    print(a)
